package com.yu.transport.handler;

import com.yu.factory.SingletonFactory;
import com.yu.transfer.RpcMessage;
import com.yu.transfer.RpcRequest;
import com.yu.transfer.RpcResponse;
import com.yu.transport.constants.NettyConstants;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.util.ReferenceCountUtil;
import lombok.extern.slf4j.Slf4j;

import java.net.InetSocketAddress;

/**
 * @PackageName: com.yu.transport.handler
 * @Description:
 * @Version: v1.0.0
 * @Author: yuweilin
 * @Date: 10:04
 * <p>
 * Modification History:
 * Date         Author          Version            Description
 * ------------------------------------------------------------
 * 2021/2/5      yuweilin         v1.0.0               新建
 */
@Slf4j
public class NettyServerHandler extends ChannelInboundHandlerAdapter {
    private final NettyRequestHandler requestHandler;

    public NettyServerHandler() {
        this.requestHandler = SingletonFactory.getInstance(NettyRequestHandler.class);
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        try {
            if (msg instanceof RpcMessage){
                log.info("收到信息{}",msg);
                RpcMessage reMessage = (RpcMessage) msg;
                RpcMessage message = new RpcMessage();
                byte messageType = reMessage.getMessageType();
                if (messageType==NettyConstants.HEARTBEAT_TYPE){
                    log.info("收到客户端：{}的一条心跳信息：{}",((InetSocketAddress)ctx.channel().remoteAddress())
                            .getAddress().getHostAddress(),NettyConstants.PING);
                    return;
                }
                RpcRequest request = (RpcRequest) reMessage.getData();
                Object result = requestHandler.handle(request);
                log.info("执行服务，返回一个结果对象:{}",result);
                message.setMessageType(NettyConstants.RESPONSE_TYPE);
                if (ctx.channel().isActive()&&ctx.channel().isWritable()){
                    RpcResponse<Object> response = RpcResponse.success(result, request.getRequestId());
                    message.setData(response);
                }else {
                    RpcResponse<Object> response = RpcResponse.fail();
                    message.setData(response);
                    log.error("远端调用失败");
                }
                ctx.writeAndFlush(message).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
            }
        }finally {
            ReferenceCountUtil.release(msg);
        }
    }
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        log.error("server catch exception");
        cause.printStackTrace();
        ctx.close();
    }
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof IdleStateEvent) {
            IdleState state = ((IdleStateEvent) evt).state();
            if (state == IdleState.READER_IDLE) {
                log.info("idle check happen, so close the connection");
                ctx.close();
            }
        } else {
            super.userEventTriggered(ctx, evt);
        }
    }
}
